package cc.aiee.alipay.api;

import java.util.Map;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayFundAuthOrderAppFreezeModel;
import com.alipay.api.domain.AlipayFundAuthOrderUnfreezeModel;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradePayModel;
import com.alipay.api.request.AlipayFundAuthOrderAppFreezeRequest;
import com.alipay.api.request.AlipayFundAuthOrderUnfreezeRequest;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayFundAuthOrderAppFreezeResponse;
import com.alipay.api.response.AlipayFundAuthOrderUnfreezeResponse;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradePayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;

import cc.aiee.alipay.config.AliPayConfig;
import cc.aiee.alipay.config.AliPayConfigKit;
import cc.aiee.alipay.core.pojo.dto.AliPayTradeAppDTO;
import cc.aiee.alipay.core.pojo.dto.refund.AliPayRefundDTO;
import cc.aiee.alipay.core.tool.AliPayTool;
import cc.aiee.alipay.model.AliPayAppPayModel;
import cc.aiee.alipay.model.AliPayAppRefundModel;
import cc.aiee.alipay.model.freeze.AliPayFreezeMinAppModel;
import cc.aiee.alipay.model.freeze.AliPayUnfreezeModel;
import cc.aiee.core.kit.KitJson;
import cc.aiee.core0.bean.R;
import cc.aiee.core0.enums.MsgCodeEnum;
import cc.aiee.core0.enums.StatusEnum;
import cc.aiee.core0.kit.KitMoney;
import cc.aiee.core0.utils.ValidUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;

public class AliPayApi {

	/**
	 * 调用支付宝接口: alipay.trade.app.pay(app支付接口2.0)
	 * 
	 * @param paymodel
	 * @param config
	 * @return
	 */
	public R<AliPayTradeAppDTO> tradeAppPay(AliPayAppPayModel paymodel, AliPayConfig config) {
		ValidUtil.asserts(paymodel);

		// 实例化客户端
//		AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", APP_ID,
//				APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2");
		AlipayClient alipayClient = AliPayConfigKit.getAlipayClient(config);
		// 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
		AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
		// SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
		AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();

		if (StrUtil.isNotBlank(paymodel.getBody())) {
			model.setBody(paymodel.getBody());
		}

		model.setSubject(paymodel.getSubject());
		model.setOutTradeNo(paymodel.getOrderNo());
//		model.setTimeoutExpress("30m");

		Integer totalAmount = paymodel.getTotalAmount();
		String yuanStr = KitMoney.toYuanStr(totalAmount);

		model.setTotalAmount(yuanStr);
		model.setProductCode("QUICK_MSECURITY_PAY");
		request.setBizModel(model);

		if (StrUtil.isBlank(paymodel.getNotifyUrl())) {
			paymodel.setNotifyUrl(config.getNotifyUrl());
		}
		request.setNotifyUrl(paymodel.getNotifyUrl());
		try {
			// 这里和普通的接口调用不同，使用的是sdkExecute
			AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
			if (false == response.isSuccess()) {
				return new R<>(response.getCode(), response.getMsg(), StatusEnum.FAIL);
			}
//			System.out.println(response.getBody());// 就是orderString 可以直接给客户端请求，无需再做处理。
			return new R<>(MsgCodeEnum.SUCCESS, new AliPayTradeAppDTO(config.getAppId(), response.getBody()));
		} catch (AlipayApiException e) {
			e.printStackTrace();
			return new R<>(MsgCodeEnum.F_EXCEPTION_2);
		}

	}

	/**
	 * 调用支付宝官网接口 : alipay.trade.refund(统一收单交易退款接口)
	 * 
	 * @param model
	 * @param config
	 * @return
	 */
	public R<AliPayRefundDTO> refund(AliPayAppRefundModel model, AliPayConfig config) {
		ValidUtil.asserts(model);
		try {
			AlipayClient alipayClient = AliPayConfigKit.getAlipayClient(config);
			AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();// 创建API对应的request类

			Integer refund_amount = model.getRefund_amount();
			String yuanStr = KitMoney.toYuanStr(refund_amount);

			Map<String, Object> beanToMap = BeanUtil.beanToMap(model);

			beanToMap.replace("refund_amount", yuanStr);

			String jsonString = KitJson.toJSONString(beanToMap);

			request.setBizContent(jsonString);
			AlipayTradeRefundResponse response = alipayClient.execute(request);// 通过alipayClient调用API，获得对应的response类
			if (false == response.isSuccess()) {
				return new R<>(response.getCode(), AliPayTool.getMsg(response), StatusEnum.FAIL);
			}
			String body = response.getBody();

			JSONObject jso = JSONObject.parseObject(body);

			String sign = jso.getString("sign");
			AliPayRefundDTO dto = jso.getObject("alipay_trade_refund_response", AliPayRefundDTO.class);
			if (dto != null && dto.ok()) {
				dto.setSign(sign);
				return new R<>(MsgCodeEnum.SUCCESS, dto);
			}
			return new R<>(dto.getCode(), dto.getMsg(), StatusEnum.FAIL);
		} catch (AlipayApiException e) {
			e.printStackTrace();
		}
		return new R<>(MsgCodeEnum.F_EXCEPTION_2);
	}

	/**
	 * 调用支付宝接口: alipay.fund.auth.order.app.freeze(线上资金授权冻结接口)
	 * 
	 * @param data
	 * @param config
	 * @return
	 */
	public R<AliPayTradeAppDTO> freezeCreate(AliPayFreezeMinAppModel data, AliPayConfig config) {
		ValidUtil.asserts(data);
		try {
			AlipayClient alipayClient = AliPayConfigKit.getAlipayClient(config);
			AlipayFundAuthOrderAppFreezeRequest request = new AlipayFundAuthOrderAppFreezeRequest();
			AlipayFundAuthOrderAppFreezeModel model = new AlipayFundAuthOrderAppFreezeModel();
			model.setOrderTitle(data.getOrderTitle());
			model.setOutOrderNo(data.getOrderNo());// 替换为实际订单号
			if (StrUtil.isBlank(data.getOutRequestNo())) {
				data.setOutRequestNo(data.getOrderNo());
			}
			model.setOutRequestNo(data.getOutRequestNo());// 替换为实际请求单号，保证每次请求都是唯一的
			model.setPayeeUserId(config.getPayeeUserId());// payee_user_id,Payee_logon_id不能同时为空
			if (data.getPayeeLogonId() != null) {
				model.setPayeeLogonId(data.getPayeeLogonId());
			}
			model.setProductCode("PRE_AUTH_ONLINE");// PRE_AUTH_ONLINE为固定值，不要替换

			Integer amount = data.getAmount();
			String yuanStr = KitMoney.toYuanStr(amount);
			model.setAmount(yuanStr);
			// 需要支持信用授权，该字段必传,芝麻信用分现在已经无法申请了
//			model.setExtraParam(
//					"{\"category\":\"CHARGE_PILE_CAR\",\"outStoreCode\":\"charge001\",\"outStoreAlias\":\"充电桩北京路点\"}"); // outStoreAlias将在用户端信用守护、支付信息、账单详情页展示
			request.setBizModel(model);
			if (StrUtil.isBlank(data.getNotifyUrl())) {
				data.setNotifyUrl(config.getNotifyUrlFreeze());
			}
			request.setNotifyUrl(data.getNotifyUrl());// 异步通知地址，必填，该接口只通过该参数进行异步通知
			AlipayFundAuthOrderAppFreezeResponse response = alipayClient.sdkExecute(request);// 注意这里是sdkExecute，可以获取签名参数
			if (response.isSuccess()) {
				// System.out.println("调用成功");
				// System.out.println(response.getBody());// 签名后的参数，直接作为 orderStr
				// 入参到my.tradePay接口
				return new R<>(MsgCodeEnum.SUCCESS, new AliPayTradeAppDTO(config.getAppId(), response.getBody()));
			} else {
				return new R<>(response.getCode(), AliPayTool.getMsg(response), StatusEnum.FAIL);
			}
		} catch (AlipayApiException e) {
			e.printStackTrace();
		}
		return new R<>(MsgCodeEnum.F_EXCEPTION_2);
	}

	/**
	 * 调用接口 : alipay.fund.auth.order.unfreeze(资金授权解冻接口)
	 * 
	 * @param data
	 * @param config
	 * @return 需要判断status==SUCCESS
	 */
	public R<AlipayFundAuthOrderUnfreezeResponse> unFreeze(AliPayUnfreezeModel data, AliPayConfig config) {
		ValidUtil.asserts(data);
		try {
			AlipayClient alipayClient = AliPayConfigKit.getAlipayClient(config);
			AlipayFundAuthOrderUnfreezeRequest request = new AlipayFundAuthOrderUnfreezeRequest();
			AlipayFundAuthOrderUnfreezeModel model = new AlipayFundAuthOrderUnfreezeModel();
			model.setAuthNo(data.getAuthNo()); // 支付宝预授权订单号，在授权冻结成功时返回需要入库保存
			if (StrUtil.isBlank(data.getOutRequestNo())) {
				String outRequestNo = "Unfreeze" + data.getAuthNo();
				if (outRequestNo.length() > 64) {
					outRequestNo = outRequestNo.substring(0, 64);
				}
				data.setOutRequestNo(outRequestNo);
			}

			model.setOutRequestNo(data.getOutRequestNo());// 同一商户每次不同的资金操作请求，商户请求流水号不能重复,且与冻结流水号不同

			Integer amount = data.getAmount();
			String yuanStr = KitMoney.toYuanStr(amount);
			model.setAmount(yuanStr); // 本次操作解冻的金额，单位为：元（人民币），精确到小数点后两位
			model.setRemark(data.getRemark()); // 商户对本次解冻操作的附言描述，长度不超过100个字母或50个汉字
			request.setBizModel(model);
			AlipayFundAuthOrderUnfreezeResponse response = alipayClient.execute(request);
			// logger.info("response: {}"+response.getBody());

			if (response.isSuccess()) {
				return new R<>(MsgCodeEnum.SUCCESS, response);
			}
			return new R<>(response.getCode(), AliPayTool.getMsg(response), StatusEnum.FAIL);
		} catch (AlipayApiException e) {
			e.printStackTrace();
		}
		return new R<>(MsgCodeEnum.F_EXCEPTION_2);
	}

	/**
	 * 接口 :alipay.trade.pay(统一收单交易支付接口)
	 * <p>
	 * 场景: 资金冻结转支付场景
	 * </p>
	 * 
	 * @param model
	 * @param config
	 * @return
	 */
	public R<AlipayTradePayResponse> tradePay(AlipayTradePayModel model, AliPayConfig config) {
		try {
			AlipayClient alipayClient = AliPayConfigKit.getAlipayClient(config);
			AlipayTradePayRequest request = new AlipayTradePayRequest();
//		AlipayTradePayModel model = new AlipayTradePayModel();
//	    model.setOutTradeNo("20180412100020088982"); // 预授权转支付商户订单号，为新的商户交易流水号
//	    model.setProductCode("PRE_AUTH_ONLINE"); // 固定值PRE_AUTH_ONLINE
//	    model.setAuthNo("2018041210002001660228733635"); // 填写预授权冻结交易号
//	    model.setSubject("预授权转支付测试"); // 解冻转支付标题，用于展示在支付宝账单中
//	    model.setTotalAmount("0.01"); // 结算支付金额
//	    model.setSellerId(pid); // 填写卖家支付宝账户pid
//	    model.setBuyerId(pay_user_id); // 填写预授权用户uid，通过预授权冻结接口返回的payer_user_id字段获取
//	    model.setStoreId("test_store_id"); // 填写实际交易发生的终端编号，与预授权的outStoreCode保持一致即可   
//	    model.setBody("预授权解冻转支付测试"); // 可填写备注信息
//	    model.setAuthConfirmMode("COMPLETE");//传入COMPLETE时,用户剩余金额会自动解冻

			if (StrUtil.isBlank(model.getSellerId())) {
				model.setSellerId(config.getPayeeUserId());
			}
			request.setBizModel(model);
			AlipayTradePayResponse response = alipayClient.execute(request);
			if (response.isSuccess()) {
				// System.out.println("调用成功");
				// logger.info("response: {}" + response.getBody());
				return new R<>(response.getCode(), response.getMsg(), StatusEnum.SUCCESS, response);
			} else {
				// System.out.println("调用失败");
				return new R<>(response.getCode(), AliPayTool.getMsg(response), StatusEnum.FAIL);
			}
		} catch (AlipayApiException e) {
			e.printStackTrace();
		}
		return new R<>(MsgCodeEnum.F_EXCEPTION_2);
	}
}
